package com.youlai.boot.payment.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayFundTransToaccountTransferRequest;
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayFundTransToaccountTransferResponse;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.youlai.boot.common.exception.BusinessException;
import com.youlai.boot.core.security.util.SecurityUtils;
import com.youlai.boot.payment.entity.RechargeOrder;
import com.youlai.boot.payment.service.AlipayService;
import com.youlai.boot.payment.mapper.RechargeOrderMapper;
import com.youlai.boot.system.converter.NoticeConverter;
import com.youlai.boot.system.mapper.NoticeMapper;
import com.youlai.boot.system.mapper.UserMapper;
import com.youlai.boot.system.mapper.UserPointsMapper;
import com.youlai.boot.system.model.entity.Notice;
import com.youlai.boot.system.model.entity.User;
import com.youlai.boot.system.model.entity.UserPoints;
import com.youlai.boot.system.model.form.NoticeForm;
import com.youlai.boot.system.model.form.RechargeForm;
import com.youlai.boot.system.service.NoticeService;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @author 张雨润
 * @date 2025/4/23 18:35
 * @Description 支付宝支付服务实现类
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class AlipayServiceImpl implements AlipayService {

    private final RechargeOrderMapper rechargeOrderMapper;
    private final UserMapper userMapper;
    private final UserPointsMapper userPointsMapper;
    private final NoticeService noticeService;
    private final NoticeConverter noticeConverter;
    private final NoticeMapper noticeMapper;

    @Value("${alipay.appId}")
    private String appId;

    @Value("${alipay.privateKey}")
    private String privateKey;

    @Value("${alipay.alipayPublicKey}")
    private String alipayPublicKey;

    @Value("${alipay.notifyUrl}")
    private String notifyUrl;

    @Value("${alipay.gatewayUrl}")
    private String gatewayUrl;

    /**
     * 创建支付宝支付订单并生成支付二维码
     *
     * @param rechargeForm 充值表单
     * @return 包含支付二维码内容的订单信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> createPayOrder(RechargeForm rechargeForm) {
        // 获取当前用户ID
        Long userId = SecurityUtils.getUserId();
        if (userId == null) {
            throw new BusinessException("用户未登录");
        }

        // 校验充值金额
        BigDecimal amount = rechargeForm.getAmount();
        if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0 || amount.scale() > 2) {
            throw new BusinessException("充值金额不合法");
        }

        // 生成订单号
        String orderNo = UUID.randomUUID().toString().replace("-", "");

        // 创建充值订单记录
        RechargeOrder rechargeOrder = new RechargeOrder();
        rechargeOrder.setUserId(userId);
        rechargeOrder.setAmount(amount);
        rechargeOrder.setOrderNo(orderNo);
        rechargeOrder.setPayType(rechargeForm.getPayType());
        rechargeOrder.setStatus(0); // 待支付状态
        rechargeOrderMapper.insert(rechargeOrder);

        try {
            // 创建AlipayClient
            AlipayClient alipayClient = new DefaultAlipayClient(
                    gatewayUrl,
                    appId,
                    privateKey,
                    "json",
                    "UTF-8",
                    alipayPublicKey,
                    "RSA2");

            // 使用预下单接口生成二维码
            com.alipay.api.request.AlipayTradePrecreateRequest request = new com.alipay.api.request.AlipayTradePrecreateRequest();
            request.setNotifyUrl(notifyUrl);

            // 组装业务参数
            Map<String, Object> bizContent = new HashMap<>();
            bizContent.put("out_trade_no", orderNo);
            bizContent.put("total_amount", amount.toString());
            bizContent.put("subject", "账户充值");
            request.setBizContent(com.alibaba.fastjson.JSON.toJSONString(bizContent));

            // 调用支付宝接口
            com.alipay.api.response.AlipayTradePrecreateResponse response = alipayClient.execute(request);
            if (!response.isSuccess()) {
                throw new BusinessException("创建支付订单失败：" + response.getMsg());
            }

            // 获取支付宝返回的二维码内容，直接返回给前端，让前端自己生成二维码
            String qrCode = response.getQrCode();

            // 返回二维码内容和订单信息
            Map<String, Object> result = new HashMap<>();
            result.put("orderNo", orderNo);
            result.put("qrCodeContent", qrCode);
            result.put("amount", amount.toString());
            return result;
        } catch (AlipayApiException e) {
            log.error("创建支付宝支付订单异常", e);
            throw new BusinessException("创建支付订单异常：" + e.getMessage());
        }
    }

    /**
     * 处理支付宝支付结果通知
     *
     * @param params 支付宝回调参数
     * @return 处理结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String handlePayNotify(Map<String, String> params) {
        try {
            // 验证签名
            boolean signVerified = AlipaySignature.rsaCheckV1(
                    params,
                    alipayPublicKey,
                    "UTF-8",
                    "RSA2");

            if (!signVerified) {
                return "failure";
            }

            // 获取交易状态
            String tradeStatus = params.get("trade_status");
            String orderNo = params.get("out_trade_no");

            // 查询订单
            RechargeOrder order = getOrderByOrderNo(orderNo);
            if (order == null) {
                return "failure";
            }

            // 如果订单已处理，直接返回成功
            if (order.getStatus() == 1) {
                return "success";
            }

            // 交易成功或交易完成
            if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)) {
                // 1. 更新订单状态
                order.setStatus(1); // 已支付
                order.setPayTime(LocalDateTime.now());
                rechargeOrderMapper.updateById(order);

                // 2. 更新用户余额
                User user = userMapper.selectById(order.getUserId());
                if (user != null) {
                    user.setBalance(user.getBalance().add(order.getAmount()));
                    userMapper.updateById(user);
                }

                // 3. 新增发布用户支付成功通知
                try {
                    sendRechargeSuccessNotice(order);
                } catch (Exception e) {
                    log.error("发送充值成功通知失败", e);
                    // 捕获异常，避免影响主事务
                }

                return "success";
            }

            return "failure";
        } catch (Exception e) {
            log.error("处理支付宝回调异常", e);
            return "failure";
        }
    }

    /**
     * 查询支付订单状态
     *
     * @param orderNo 订单号
     * @return 订单状态
     */
    @Override
    public String queryPayStatus(String orderNo) {
        try {
            AlipayClient alipayClient = new DefaultAlipayClient(
                    gatewayUrl,
                    appId,
                    privateKey,
                    "json",
                    "UTF-8",
                    alipayPublicKey,
                    "RSA2");

            AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
            Map<String, Object> bizContent = new HashMap<>();
            bizContent.put("out_trade_no", orderNo);
            request.setBizContent(com.alibaba.fastjson.JSON.toJSONString(bizContent));

            AlipayTradeQueryResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                return response.getTradeStatus();
            }
            return null;
        } catch (AlipayApiException e) {
            log.error("查询支付宝订单状态异常", e);
            return null;
        }
    }

    /**
     * 根据订单号获取充值订单
     *
     * @param orderNo 订单号
     * @return 充值订单
     */
    @Override
    public RechargeOrder getOrderByOrderNo(String orderNo) {
        return rechargeOrderMapper.selectOne(
                new LambdaQueryWrapper<RechargeOrder>()
                        .eq(RechargeOrder::getOrderNo, orderNo));
    }

    /**
     * 根据用户ID和用户名获取充值历史列表
     *
     * @param userId   用户ID
     * @param username 用户名
     * @return 充值历史列表
     */
    @Override
    public IPage<RechargeOrder> getRechargeList(Long userId, String username, Integer pageNum, Integer pageSize) {
        // 构建分页对象
        Page<RechargeOrder> page = new Page<>(pageNum, pageSize);

        // 构建查询条件
        LambdaQueryWrapper<RechargeOrder> queryWrapper = new LambdaQueryWrapper<RechargeOrder>()
                .eq(userId != null, RechargeOrder::getUserId, userId)
                .orderByDesc(RechargeOrder::getCreateTime);

        // 如果用户名不为空，添加模糊查询条件
        if (StrUtil.isNotBlank(username)) {
            // 获取所有匹配用户名的用户ID
            List<Long> userIds = userMapper.selectList(
                    new LambdaQueryWrapper<User>()
                            .like(User::getUsername, username)
                            .select(User::getId))
                    .stream().map(User::getId).toList();

            // 如果没有找到匹配的用户，直接返回空分页对象
            if (userIds.isEmpty()) {
                return page;
            }

            // 添加用户ID条件
            queryWrapper.in(RechargeOrder::getUserId, userIds);
        }

        // 执行分页查询
        return rechargeOrderMapper.selectPage(page, queryWrapper);
    }

    /**
     * 积分充值，RMB-->积分
     * 
     * @param rechargeForm amount为积分
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean rechargeExchange(RechargeForm rechargeForm) {
        Long userId = SecurityUtils.getUserId();
        BigDecimal amount = rechargeForm.getAmount();

        // 校验输入参数
        if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            return false;
        }

        // 获取用户信息
        User user = userMapper.selectById(userId);
        if (user == null) {
            return false;
        }

        // 扣减账户余额
        try {
            deductBalance(user, amount);
        } catch (Exception e) {
            return false;
        }

        // 增加积分余额
        try {
            updateUserPoints(userId, amount);
        } catch (Exception e) {
            return false;
        }

        // 发送积分充值成功通知
        try {
            sendPointsExchangeNotice(userId, amount);
        } catch (Exception e) {
            log.error("发送积分充值成功通知失败", e);
            // 捕获异常，避免影响主事务
        }

        return true;
    }

    /**
     * 账户提现
     *
     * @param alipayAccount 支付宝账号
     * @param amount        提现金额
     * @return 提现结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean withdraw(String alipayAccount, String alipayRealName, BigDecimal amount) {
        // 1. 验证参数
        if (StrUtil.isBlank(alipayAccount) || StrUtil.isBlank(alipayRealName) || amount == null
                || amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("提现参数不合法");
        }

        // 2. 获取当前用户并验证余额
        Long userId = SecurityUtils.getUserId();
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        if (user.getBalance().compareTo(amount) < 0) {
            throw new BusinessException("账户余额不足");
        }

        try {
            // 3. 调用支付宝转账接口
            AlipayClient alipayClient = new DefaultAlipayClient(
                    gatewayUrl,
                    appId,
                    privateKey,
                    "json",
                    "UTF-8",
                    alipayPublicKey,
                    "RSA2");

            AlipayFundTransToaccountTransferRequest request = new AlipayFundTransToaccountTransferRequest();

            Map<String, Object> bizContent = new HashMap<>();
            bizContent.put("out_biz_no", UUID.randomUUID().toString().replace("-", ""));
            bizContent.put("payee_type", "ALIPAY_LOGONID");
            bizContent.put("payee_account", alipayAccount);
            bizContent.put("payee_real_name", alipayRealName);
            bizContent.put("amount", amount.toString());
            bizContent.put("product_code", "TRANS_ACCOUNT_NO_PWD");
            bizContent.put("biz_scene", "DIRECT_TRANSFER");
            request.setBizContent(JSON.toJSONString(bizContent));

            AlipayFundTransToaccountTransferResponse response = alipayClient.execute(request);
            if (!response.isSuccess()) {
                throw new BusinessException("支付宝提现失败: " + response.getSubMsg());
            }

            // 4. 更新用户余额
            user.setBalance(user.getBalance().subtract(amount));
            userMapper.updateById(user);

            // 5. 记录提现流水
            RechargeOrder withdrawRecord = new RechargeOrder();
            withdrawRecord.setUserId(userId);
            withdrawRecord.setAmount(amount.negate()); // 负数表示提现
            withdrawRecord.setOrderNo(response.getOutBizNo());
            withdrawRecord.setPayType(2); // 提现类型
            withdrawRecord.setStatus(1); // 已完成
            withdrawRecord.setPayTime(LocalDateTime.now());
            rechargeOrderMapper.insert(withdrawRecord);

            // 6. 发送提现成功通知
            try {
                sendWithdrawSuccessNotice(userId, amount, alipayAccount);
            } catch (Exception e) {
                log.error("发送提现成功通知失败", e);
                // 捕获异常，避免影响主事务
            }

            return true;
        } catch (AlipayApiException e) {
            log.error("支付宝提现异常", e);
            throw new BusinessException("提现处理异常: " + e.getMessage());
        }
    }

    /**
     * 发送提现成功通知
     * 
     * @param userId        用户ID
     * @param amount        提现金额
     * @param alipayAccount 支付宝账号
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    protected void sendWithdrawSuccessNotice(Long userId, BigDecimal amount, String alipayAccount) {
        NoticeForm form = NoticeForm.builder()
                .title("账户提现成功")
                .content(
                        "<div style='font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);'>"
                                +
                                "<h2 style='color: #4CAF50; margin-bottom: 20px;'>提现成功通知</h2>" +
                                "<div style='background-color: #f9f9f9; padding: 15px; border-radius: 5px;'>" +
                                "<p style='margin: 10px 0;'><strong>提现金额：</strong><span style='color: #FF5722; font-weight: bold;'>¥"
                                + amount + "</span></p>" +
                                "<p style='margin: 10px 0;'><strong>到账账号：</strong>" + alipayAccount + "</p>" +
                                "<p style='margin: 10px 0;'><strong>提现时间：</strong>"
                                + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
                                + "</p>" +
                                "</div>" +
                                "<p style='margin-top: 20px; color: #666;'>提现金额预计1-3个工作日内到账，如有疑问请联系客服。</p>" +
                                "</div>")
                .level("L")
                .targetType(2)
                .type(5)
                .targetUserIds(Collections.singletonList(String.valueOf(userId)))
                .build();

        Notice entity = noticeConverter.toEntity(form);
        // 新建通知
        entity.setCreateBy(userId);
        entity.setPublisherId(userId);
        noticeMapper.insert(entity);

        // 发布通知
        noticeService.publishNotice(entity.getId());
    }

    /**
     * 扣减用户账户余额
     * 
     * @param user   用户对象
     * @param amount 扣减金额
     */
    private void deductBalance(User user, BigDecimal amount) {
        BigDecimal balanceToDeduct = amount.multiply(BigDecimal.valueOf(2));
        user.setBalance(user.getBalance().subtract(balanceToDeduct));
        userMapper.updateById(user);
    }

    /**
     * 更新用户积分余额
     * 
     * @param userId 用户ID
     * @param amount 增加的积分
     */
    private void updateUserPoints(Long userId, BigDecimal amount) {
        UserPoints userPoints = userPointsMapper.selectOne(
                new LambdaQueryWrapper<UserPoints>().eq(UserPoints::getUserId, userId));

        if (userPoints == null) {
            userPoints = UserPoints.builder()
                    .userId(userId)
                    .totalPoints(amount)
                    .remainPoints(amount)
                    .build();
            userPointsMapper.insert(userPoints);
        } else {
            userPoints.setTotalPoints(userPoints.getTotalPoints().add(amount));
            userPoints.setRemainPoints(userPoints.getRemainPoints().add(amount));
            userPointsMapper.updateById(userPoints);
        }
    }

    /**
     * 新增发布用户支付成功通知
     * 
     * @param order
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    protected void sendRechargeSuccessNotice(RechargeOrder order) {
        NoticeForm form = NoticeForm.builder()
                .title("账户余额充值成功")
                .content(
                        "<div style='font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);'>"
                                +
                                "<h2 style='color: #4CAF50; margin-bottom: 20px;'>充值成功通知</h2>" +
                                "<div style='background-color: #f9f9f9; padding: 15px; border-radius: 5px;'>" +
                                "<p style='margin: 10px 0;'><strong>订单号：</strong>" + order.getOrderNo() + "</p>"
                                +
                                "<p style='margin: 10px 0;'><strong>充值金额：</strong><span style='color: #FF5722; font-weight: bold;'>¥"
                                + order.getAmount() + "</span></p>" +
                                "<p style='margin: 10px 0;'><strong>充值时间：</strong>"
                                + order.getPayTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
                                + "</p>" +
                                "<p style='margin: 10px 0;'><strong>支付方式：</strong>支付宝</p>" +
                                "</div>" +
                                "<p style='margin-top: 20px; color: #666;'>感谢您的充值，如有疑问请联系客服。</p>" +
                                "</div>")
                .level("L")
                .targetType(2)
                .type(5)
                .targetUserIds(Collections.singletonList(String.valueOf(order.getUserId())))
                .build();

        Notice entity = noticeConverter.toEntity(form);
        // 新建通知
        entity.setCreateBy(order.getUserId());
        entity.setPublisherId(order.getUserId());
        noticeMapper.insert(entity);

        // 发布通知
        noticeService.publishNotice(entity.getId());
    }

    /**
     * 新增发布用户积分充值成功通知
     * 
     * @param userId 用户ID
     * @param points 充值积分
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    protected void sendPointsExchangeNotice(Long userId, BigDecimal points) {
        NoticeForm form = NoticeForm.builder()
                .title("积分余额充值成功")
                .content(
                        "<div style='font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);'>"
                                +
                                "<h2 style='color: #4CAF50; margin-bottom: 20px;'>积分充值成功通知</h2>" +
                                "<div style='background-color: #f9f9f9; padding: 15px; border-radius: 5px;'>" +
                                "<p style='margin: 10px 0;'><strong>充值积分：</strong><span style='color: #FF5722; font-weight: bold;'>"
                                + points + "</span></p>" +
                                "<p style='margin: 10px 0;'><strong>消耗金额：</strong><span style='color: #FF5722; font-weight: bold;'>¥"
                                + points.multiply(BigDecimal.valueOf(2)) + "</span></p>" +
                                "<p style='margin: 10px 0;'><strong>充值时间：</strong>"
                                + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
                                + "</p>" +
                                "</div>" +
                                "<p style='margin-top: 20px; color: #666;'>感谢您的积分充值，如有疑问请联系客服。</p>" +
                                "</div>")
                .level("L")
                .targetType(2)
                .type(5)
                .targetUserIds(Collections.singletonList(String.valueOf(userId)))
                .build();

        Notice entity = noticeConverter.toEntity(form);
        // 新建通知
        entity.setCreateBy(userId);
        entity.setPublisherId(userId);
        noticeMapper.insert(entity);

        // 发布通知
        noticeService.publishNotice(entity.getId());
    }
}